#pragma once
#include "types.hpp"
#include "platform.hpp"
#include "thread/atomiccounter.hpp"
using namespace JHCPP::thread;
#include <vector>
#include <map>

#if defined(JH_OS_WINDOWS)
#include <Windows.h>
#elif defined(JH_OS_LINUX)

#endif

namespace JHCPP
{
	namespace filesys
	{
		class CPipe;

	#if defined(JH_OS_WINDOWS)
		class CProcessHandleImpl : public CRefCountedObject
		{
		public:
			CProcessHandleImpl(HANDLE hProcess, UInt32 pid);
			~CProcessHandleImpl();

			UInt32 id() const;
			HANDLE process() const;
			int wait() const;

		private:
			HANDLE m_hProcess;
			UInt32 m_pid;

			CProcessHandleImpl(const CProcessHandleImpl&);
			CProcessHandleImpl& operator = (const CProcessHandleImpl&);
		};

		class CProcessImpl
		{
		public:
			typedef UInt32 PIDImpl;
			typedef std::vector<std::string> ArgsImpl;
			typedef std::map<std::string, std::string> EnvImpl;

			static PIDImpl idImpl();
			static void timesImpl(long& userTime, long& kernelTime);
			static CProcessHandleImpl* launchImpl(
				const std::string& command, 
				const ArgsImpl& args, 
				const std::string& initialDirectory,
				CPipe* inPipe, 
				CPipe* outPipe, 
				CPipe* errPipe,
				const EnvImpl& env);
			static void killImpl(const CProcessHandleImpl& handle);
			static void killImpl(PIDImpl pid);
			static void requestTerminationImpl(PIDImpl pid);
			static std::string terminationEventName(PIDImpl pid);
		};
	#elif defined(JH_OS_LINUX)

		class CProcessHandleImpl : public CRefCountedObject
		{
		public:
			CProcessHandleImpl(pid_t pid);
			~CProcessHandleImpl();

			pid_t id() const;
			int wait() const;

		private:
			pid_t m_pid;
		};

		class CProcessImpl
		{
		public:
			typedef pid_t PIDImpl;
			typedef std::vector<std::string> ArgsImpl;
			typedef std::map<std::string, std::string> EnvImpl;

			static PIDImpl idImpl();
			static void timesImpl(long& userTime, long& kernelTime);
			static CProcessHandleImpl* launchImpl(
				const std::string& command, 
				const ArgsImpl& args, 
				const std::string& initialDirectory,
				CPipe* inPipe, 
				CPipe* outPipe, 
				CPipe* errPipe,
				const EnvImpl& env);
			static void killImpl(const CProcessHandleImpl& handle);
			static void killImpl(PIDImpl pid);
			static void requestTerminationImpl(PIDImpl pid);

		private:
			static CProcessHandleImpl* launchByForkExecImpl(
				const std::string& command, 
				const ArgsImpl& args, 
				const std::string& initialDirectory,
				CPipe* inPipe, 
				CPipe* outPipe, 
				CPipe* errPipe,
				const EnvImpl& env);
		};
	#endif

		class CProcessHandle
		{
		public:
			typedef CProcessImpl::PIDImpl PID;

			CProcessHandle(const CProcessHandle& handle);
			~CProcessHandle();

			CProcessHandle& operator = (const CProcessHandle& handle);

			PID id() const;

			int wait() const;
	
		protected:
			CProcessHandle(CProcessHandleImpl* pImpl);

		private:
			CProcessHandle();
			CProcessHandleImpl* m_pImpl;
			friend class CProcess;
		};

		class CProcess : public CProcessImpl
		{
		public:
			typedef PIDImpl  PID;
			typedef ArgsImpl Args;
			typedef EnvImpl  Env;

			static PID id();

			static void times(long& userTime, long& kernelTime);

			static CProcessHandle launch(const std::string& command, const Args& args);

			static CProcessHandle launch(
				const std::string& command, 
				const Args& args, 
				const std::string& initialDirectory);

			static CProcessHandle launch(
				const std::string& command, 
				const Args& args, 
				CPipe* inPipe, 
				CPipe* outPipe, 
				CPipe* errPipe);

			static CProcessHandle launch(
				const std::string& command, 
				const Args& args, 
				const std::string& initialDirectory,
				CPipe* inPipe, 
				CPipe* outPipe, 
				CPipe* errPipe);
	

			static CProcessHandle launch(
				const std::string& command, 
				const Args& args, 
				CPipe* inPipe, 
				CPipe* outPipe, 
				CPipe* errPipe,
				const Env& env);

			static CProcessHandle launch(
				const std::string& command, 
				const Args& args, 
				const std::string& initialDirectory,
				CPipe* inPipe, 
				CPipe* outPipe, 
				CPipe* errPipe,
				const Env& env);

			static int wait(const CProcessHandle& handle);
	
			static void kill(const CProcessHandle& handle);
			static void kill(PID pid);
	
			static void requestTermination(PID pid);
		};
	}//end of namespace filesys
}//end of namespace JHCPP
